你值得拥有!更省钱地完成数据监听
大家好,今天一起来了解一个新的设计模式——观察者模式。
观察者模式的思路很简单,它被广泛地应用在各种数据监控上。
很多时候我们希望监听某个数据的变化,希望一旦获悉它的变化之后便能立即采取一些举措。按照常规的操作,我们需要开启额外的线程来进行监听。但开启线程并不是最好的选择,一是因为非常麻烦,二是会带来额外的开销。
我们今天介绍的观察者模式就可以在无需多余开销的基础上完成数据监听这个功能。
观察者
在观察者模式当中,整个运行流和常规的操作相反。我们并不是用一些程序去监听数据的变化,相反,是当数据发生变化的时候,我们去通知对应的监听器数据产生了变化。好处我们前面也说过了,可以避免多余的开销。
首先,我们来实现两个监听器。当数据发生变化之后就会触发这两个监听器。在这个设计模式当中,监听器被命名为 viewer,这里的观察不是一种主动的观察,而是一种被动地接收通知。也许是起名的人想不出更好的名字来吧,其实我觉得应该叫做 receiver 更好。
class IncreaseViewer:
def __init__(self):
self.data = 0
def update(self, subject):
# 判断是否增加
if subject.data > self.data:
print('Increased: Subject {} data increased to {}'.format(subject.name, subject.data))
self.data = subject.data
class DeclineViewer:
def __init__(self):
self.data = 0
def update(self, subject):
# 判断是否减少
if subject.data < self.data:
print('Decreased: Subject %s data decreased to %d' % (subject.name, subject.data))
self.data = subject.data
数据
观察者的代码应该很好理解,理解了观察者类之后,我们再来看看数据类。
数据的类其实也很简单,我们只需要设计一个功能,让它可以在数据发生赋值操作的时候去通知一下观察者就可以了。
我们都知道在Python当中,赋值操作是没办法直接感知的,但是类当中的成员发生变化的时候,我们是可以通过@property 装饰器来进行修饰的。
所以我们就利用这一点来实现这个数据类,如果大家熟悉@property 注解的话,也非常简单。
class Data(Subject):
def __init__(self, name=''):
Subject.__init__(self)
self.name = name
self._data = 0
@property
def data(self):
return self._data
@data.setter
def data(self, data):
self._data = data
# 关键
self.notify()
大家看到了 data 这个方法当中的 self.notify 了吗?这个就是通知函数,所以就是当 Data 这个类当中的 data 成员发生变化的时候,我们执行通知操作,去通知观察者执行。
管理观察者
现在我们观察者实现好了,数据类也有了,剩下的就是把这两者连通起来了。当然,我们也可以简单粗暴地用代码实现,但是更好的做法是对数据和观察者之间的联系做一个简单的管理。因为可能不同的数据需要的观察者不一样,我们并不能一概而论。
其实管理观察者也不需要太复杂,只需要用面向对象的思路对 list 进行一个简单的封装即可。
class Subject:
def __init__(self):
self._observer = []
def attach(self, observer):
if observer not in self._observer:
self._observer.append(observer)
def detach(self, observer):
try:
self._observer.remove(observer)
except ValueError:
pass
def notify(self, modifier=None):
for observer in self._observer:
if modifier != observer:
observer.update(self)
attach 表示关联,也就是给数据关联上观察者,detach 表示解除关联,notify 自然就是通知了。
其实也就是用一个循环遍历一下所有的观察者,然后执行一下对应的 update函数就可以了。当然,如果观察者很多或者是运行效率不高的话,可以考虑一下使用多线程来并发执行。
这里为了简化逻辑,我们把 Subject 类做成了 Data 类的父类。这样某种程度上相当于解耦了观察者和数据,我们以后无论是对哪部分逻辑进行修改或者是优化都不会影响另外两方。
整个代码不过 50 行,可以说是非常简便了。不仅是 Python,对于其他支出多态的语言来说,这个设计模式也是同样适用的。
到这里关于观察者模式就介绍完了,今天的文章就到这里。衷心祝愿大家每天都有所收获。